package core

import (
	"fmt"
)

// 边界值
const (
	AOI_MIN_X  = 85
	AOI_MAX_X  = 410
	AOI_CNTS_X = 10
	AOI_MIN_Y  = 75
	AOI_MAX_Y  = 400
	AOI_CNTS_Y = 20
)

type AOIManager struct {
	//区域的左边界坐标
	MinX int
	//区域的右边界坐标
	MaxX int
	//区域的上边界坐标
	MinY int
	//区域的下边界坐标
	MaxY int
	//X方向的格子数量
	CntX int
	//Y方向的格子数量
	CntY int
	//格子ID到格子对象的映射关系
	Grids map[int]*Grid
}

func NewAOIManager(minX, maxX, minY, maxY, cntX, cntY int) *AOIManager {
	aoi := &AOIManager{
		MinX:  minX,
		MaxX:  maxX,
		MinY:  minY,
		MaxY:  maxY,
		CntX:  cntX,
		CntY:  cntY,
		Grids: make(map[int]*Grid),
	}
	//初始化每个格子
	for y := 0; y < cntY; y++ {
		for x := 0; x < cntX; x++ {
			gid := y*cntX + x
			aoi.Grids[gid] = NewGrid(gid,
				aoi.MinX+x*aoi.gridWidth(),
				aoi.MinX+(x+1)*aoi.gridWidth(),
				aoi.MinY+y*aoi.gridLength(),
				aoi.MinY+(y+1)*aoi.gridLength())
		}
	}
	return aoi
}

// 得到每个格子在X方向上的宽度
func (m *AOIManager) gridWidth() int {
	return (m.MaxX - m.MinX) / m.CntX
}

// 得到每个格子在Y方向上的长度
func (m *AOIManager) gridLength() int {
	return (m.MaxY - m.MinY) / m.CntY
}

// 打印格子管理及其格子信息
func (m *AOIManager) String() string {
	s := fmt.Sprintf("AOIManager:\nMinX:%d, MaxX:%d, MinY:%d, MaxY:%d, cntX:%d, cntY:%d\nGrids in AOIManager:\n",
		m.MinX, m.MaxX, m.MinY, m.MaxY, m.CntX, m.CntY)
	for _, grid := range m.Grids {
		s += fmt.Sprintln(grid.String())
	}
	return s
}

// GetSurroundGridsByGid 根据格子GID得到周边九宫格格子集合
func (m *AOIManager) GetSurroundGridsByGid(gID int) (grids []*Grid) {
	if _, ok := m.Grids[gID]; !ok {
		return
	}
	cx, cy := gID%m.CntX, gID/m.CntX
	for j := -1; j <= 1; j++ {
		for i := -1; i <= 1; i++ {
			nx, ny := cx+j, cy+i
			if nx >= 0 && nx < m.CntX && ny >= 0 && ny < m.CntY {
				if m.Grids[ny*m.CntX+nx] != nil {
					grids = append(grids, m.Grids[ny*m.CntX+nx])
				}
			}
		}
	}
	return grids
}

// GetGidByPos 通过x、y坐标得到当前所在格子的GID
func (m *AOIManager) GetGidByPos(x, y float32) int {
	xid, yid := (int(x)-m.MinX)/m.gridWidth(), (int(y)-m.MinY)/m.gridLength()
	return yid*m.CntX + xid
}

// GetPidsByPos 通过横纵坐标得到周边九宫格内全部的PlayerIDs
func (m *AOIManager) GetPidsByPos(x, y float32) (playerIDs []int) {
	//得到当前玩家所在格子的GID
	gid := m.GetGidByPos(x, y)
	//通过GID得到周边九宫格信息
	sur := m.GetSurroundGridsByGid(gid)
	//将九宫格的信息里的全部PlayerID累加进playerIDs
	for _, grid := range sur {
		playerIDs = append(playerIDs, grid.GetPlayerIDs()...)
		//fmt.Printf("===>grid ID = %d, pids= %v =======", grid.GID, grid.GetPlayerIDs())
	}
	return playerIDs
}

// AddPidToGrid 添加一个playerID到一个grid中
func (m *AOIManager) AddPidToGrid(pID, gID int) {
	m.Grids[pID].Add(gID)
}

// RemovePidFromGid 移除一个格子中的playerID
func (m *AOIManager) RemovePidFromGid(pID, gID int) {
	m.Grids[pID].Remove(gID)
}

// GetPidsByGid 根据GID获取全部的PID
func (m *AOIManager) GetPidsByGid(gID int) (playerIDs []int) {
	playerIDs = m.Grids[gID].GetPlayerIDs()
	return playerIDs
}

// AddToGridByPos 根据坐标将pID添加进对应的格子
func (m *AOIManager) AddToGridByPos(pID int, x, y float32) {
	gID := m.GetGidByPos(x, y)
	m.AddPidToGrid(pID, gID)
}

// RemoveFromGridByPos 通过坐标把一个player从一个格子中删除
func (m *AOIManager) RemoveFromGridByPos(pID int, x, y float32) {
	gID := m.GetGidByPos(x, y)
	m.RemovePidFromGid(pID, gID)
}
